package xyz.eden.cloud.common.web.spring;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import xyz.eden.cloud.common.core.exception.BusinessException;
import xyz.eden.cloud.common.core.exception.ParameterException;
import xyz.eden.cloud.common.core.json.JsonTool;
import xyz.eden.cloud.common.core.result.ResultSetEnum;
import xyz.eden.cloud.common.web.result.HttpResultSet;
import xyz.eden.cloud.common.web.result.HttpResultSetTool;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class HttpGlobalExceptionHandler {

    /**
     * Spring 参数校验
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {
            HttpMessageNotReadableException.class,
            MissingPathVariableException.class,
            MissingServletRequestParameterException.class
    })
    public HttpResultSet<String> handleHttpMessageNotReadableException(Exception e) {
        String message = e.getMessage();
        log.warn("Catch handleHttpMessageNotReadableException, Msg:{}.", message, e);
        String resultMsg = "Required request body is missing";
        return HttpResultSetTool.builderFail(ResultSetEnum.ERROR_PARAM.getCode(), resultMsg);
    }

    /**
     * 处理参数校验
     *
     * @param exception
     * @return
     */
    @ExceptionHandler(value = {
            MethodArgumentNotValidException.class
    })
    public HttpResultSet<List<Map<String, String>>> handlerValidException(MethodArgumentNotValidException exception) {
        BindingResult bindingResult = exception.getBindingResult();
        List<FieldError> fieldErrorList = bindingResult.getFieldErrors();
        log.info("Catch MethodArgumentNotValidException, fieldErrorInfo:{}.", JsonTool.toJsonStr(fieldErrorList));
        if (CollectionUtils.isEmpty(fieldErrorList)) {
            return HttpResultSetTool.builderFail(ResultSetEnum.ERROR_PARAM.getCode(), ResultSetEnum.ERROR_PARAM.getMsg());
        }

        List<Map<String, String>> list = fieldErrorList.stream().map(fieldError -> {
            Map<String, String> map = new HashMap<>();
            map.put("field", fieldError.getField());
            map.put("message", fieldError.getDefaultMessage());

            return map;
        }).filter(MapUtils::isNotEmpty).collect(Collectors.toList());

        FieldError fieldError = fieldErrorList.get(0);
        String field = fieldError.getField();
        String defaultMessage = fieldError.getDefaultMessage();
        String msg = field + ":" + defaultMessage;

        return HttpResultSetTool.builderResultSet(ResultSetEnum.ERROR_PARAM.getCode(), msg, list);
    }

    /**
     * 处理 ParameterException
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {
            ParameterException.class
    })
    public HttpResultSet<Object> handleParameterException(ParameterException e) {
        String message = e.getMessage();
        log.warn("Catch ParameterException, Msg:{}.", message, e);
        String resultMsg = StringUtils.isNoneBlank(message) ? message : ResultSetEnum.ERROR_PARAM.getMsg();
        return HttpResultSetTool.builderResultSet(e.getCode(), resultMsg, Objects.isNull(e.getExceptionData()) ? null : e.getExceptionData().getData());
    }

    /**
     * 处理 BusinessException
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {
            BusinessException.class
    })
    public HttpResultSet<Object> handleBusinessException(BusinessException e) {
        String message = e.getMessage();
        log.warn("Catch BusinessException, Msg:{}.", message, e);
        String resultMsg = StringUtils.isNoneBlank(message) ? message : ResultSetEnum.ERROR_BUSINESS.getMsg();
        return HttpResultSetTool.builderFail(ResultSetEnum.ERROR_BUSINESS.getCode(), resultMsg);
    }

    /**
     * 处理 Exception
     *
     * @param exception
     * @return
     */
    @ExceptionHandler(value = {
            Exception.class
    })
    public HttpResultSet<Object> handleException(Exception exception) {
        String message = exception.getMessage();
        log.error("Catch Exception, Msg:{}.", message, exception);
//        String resultMsg = StringUtils.isNoneBlank(message) ? message : ResultSetEnum.ERROR_SYSTEM.getMsg();
        if (message.startsWith("Maximum upload size exceeded")) {
            return HttpResultSetTool.builderFail(ResultSetEnum.ERROR_SYSTEM.getCode(), "上传文件过大");
        } else {
            return HttpResultSetTool.builderFail(ResultSetEnum.ERROR_SYSTEM.getCode(), "系统繁忙，请稍后再试");
        }

    }

}